package org.spark.api.util;

import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.List;

/**
 * @author chenwy
 */
public class DateUtils {

    private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
    private static DateTimeFormatter hourFormatter = DateTimeFormatter.ofPattern("yyyyMMddHH");
    private static DateTimeFormatter birthdayFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyyMM");
    private static DateTimeFormatter normalFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public static String format(DateTimeFormatter formatter, long epochMillis) {
        return formatter.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis),
                ZoneId.systemDefault()));
    }


    public static String toDayString(long epochMillis) {
        return format(formatter, epochMillis);
    }

    public static String toHourString(long epochMillis) {
        return format(hourFormatter, epochMillis);
    }

    public static String toMonthString(long epochMillis) {
        return format(monthFormatter, epochMillis);
    }


    public static LocalDateTime getLocalDateTime(long epochMillis) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.systemDefault());
    }

    public static Triple<String, String, String> getNaturalDateShard(long epochMillis) {
        LocalDateTime localDateTime = getLocalDateTime(epochMillis);
        Pair<LocalDateTime, LocalDateTime> pair = getNaturalWeekDateTimePair(epochMillis);
        String day = formatter.format(localDateTime);
        String week = formatter.format(pair.getLeft()) + "-" + formatter.format(pair.getRight());
        String month = monthFormatter.format(localDateTime);
        return Triple.of(day, week, month);
    }


    public static Pair<LocalDateTime, LocalDateTime> getNaturalWeekDateTimePair(long epochMillis) {
        LocalDateTime localDateTime = getLocalDateTime(epochMillis);
        DayOfWeek dayOfWeek = localDateTime.getDayOfWeek();
        int value = dayOfWeek.getValue();
        Pair<Integer, Integer> pair = Pair.of(value - 1, 7 - value);
        LocalDateTime monday = localDateTime.minusDays(pair.getLeft());
        LocalDateTime sunday = localDateTime.plusDays(pair.getRight());
        return Pair.of(monday, sunday);
    }


    public static Pair<String, String> getNaturalWeek(long epochMillis) {
        Pair<LocalDateTime, LocalDateTime> pair = getNaturalWeekDateTimePair(epochMillis);
        String monday = formatter.format(pair.getLeft());
        String sunday = formatter.format(pair.getRight());
        return Pair.of(monday, sunday);
    }


    public static Pair<LocalDateTime, LocalDateTime> getNaturalMonthDateTimePair(long epochMillis) {
        LocalDateTime localDateTime = getLocalDateTime(epochMillis);
        LocalDateTime firstDay = localDateTime.withDayOfMonth(1);
        LocalDateTime lastDay = localDateTime.with(TemporalAdjusters.lastDayOfMonth());
        return Pair.of(firstDay, lastDay);
    }

    /**
     * 获取两个时间之间的所有日期
     * @param start
     * @param end
     * @return
     */
    public static List<String> getRangeDayStringList(LocalDateTime start, LocalDateTime end) {
        List<String> list = new ArrayList<>();
        long between = Math.abs(ChronoUnit.DAYS.between(start, end));
        for (int i = 0; i <= between; i++) {
            LocalDateTime date = start.plusDays(i);
            list.add(formatter.format(date));
        }
        return list;
    }

    /**
     * 获取所在周的所有日期
     *
     * @param epochMillis
     * @return
     */
    public static List<String> getNaturalWeekDayStringList(long epochMillis) {
        Pair<LocalDateTime, LocalDateTime> pair = getNaturalWeekDateTimePair(epochMillis);
        return getRangeDayStringList(pair.getLeft(), pair.getRight());
    }


    /**
     * 获取传入的时间戳所在的月份的日期列表
     *
     * @param epochMillis
     * @return
     */
    public static List<String> getNaturalMonthDayStringList(long epochMillis) {
        Pair<LocalDateTime, LocalDateTime> pair = getNaturalMonthDateTimePair(epochMillis);
        return getRangeDayStringList(pair.getLeft(), pair.getRight());
    }

    /**
     * 获取传入时间戳所在的月份的所有周
     *
     * @param epochMillis
     * @return
     */
    public static List<Pair<String, String>> getNaturalMonthWeekPairList(long epochMillis) {
        Pair<LocalDateTime, LocalDateTime> pair = getNaturalMonthDateTimePair(epochMillis);
        List<Pair<String, String>> list = new ArrayList<>();
        LocalDateTime firstDay = pair.getLeft(), lastDay = pair.getRight();
        int size = lastDay.getDayOfMonth();
        size += firstDay.getDayOfWeek().getValue() - 1;
        size += 7 - lastDay.getDayOfWeek().getValue();
        firstDay = firstDay.plusDays(7 - firstDay.getDayOfWeek().getValue());
        for (int i = DayOfWeek.SUNDAY.getValue(); i <= size; i += DayOfWeek.SUNDAY.getValue()) {
            list.add(Pair.of(formatter.format(firstDay.minusDays(6)), formatter.format(firstDay)));
            firstDay = firstDay.plusDays(7);
        }
        return list;
    }


    public static void main(String[] args) {
        List<Pair<String, String>> list = getNaturalMonthWeekPairList(System.currentTimeMillis());
        for (Pair<String, String> pair : list) {
            System.out.println(pair.getLeft() + "," + pair.getRight());
        }
    }


}
